/*
 * src/pl/plpython/plpy_typeio.h
 */

#ifndef PLPY_TYPEIO_H
#define PLPY_TYPEIO_H

#include "access/htup.h"
#include "fmgr.h"
#include "plpython.h"
#include "utils/typcache.h"

struct PLyProcedure;			/* 避免在这里要求 plpy_procedure.h */


/*
 * 从 PostgreSQL Datum 到 Python 对象的“输入”转换。
 *
 * arg 是先前设置的转换数据，val 是要转换的值。
 * val 不能为空。
 *
 * 注意：转换数据结构应视为 plpy_typeio.c 的私人部分。
 * 我们在这里声明它们只是为了让其他模块可以定义包含它们的结构。
 */
typedef struct PLyDatumToOb PLyDatumToOb;	/* 前向引用 */

typedef PyObject *(*PLyDatumToObFunc) (PLyDatumToOb *arg, Datum val);

typedef struct PLyScalarToOb
{
	FmgrInfo	typfunc;		/* 类型的输出函数的查找信息 */
} PLyScalarToOb;

typedef struct PLyArrayToOb
{
	PLyDatumToOb *elm;			/* 数组元素类型的转换信息 */
} PLyArrayToOb;

typedef struct PLyTupleToOb
{
	/* 如果我们处理的是 RECORD 类型，则实际描述符在这里： */
	TupleDesc	recdesc;
	/* 如果我们处理的是命名复合类型，则这些字段被设置： */
	TypeCacheEntry *typentry;	/* 类型的 typcache 条目 */
	uint64		tupdescid;		/* typcache 中看到的最后一个 tupdesc 标识符 */
	/* 如果尚未设置，这些字段为 NULL/0： */
	PLyDatumToOb *atts;			/* 每列转换信息的数组 */
	int			natts;			/* 数组的长度 */
} PLyTupleToOb;

typedef struct PLyTransformToOb
{
	FmgrInfo	typtransform;	/* from-SQL 转换函数的查找信息 */
} PLyTransformToOb;

struct PLyDatumToOb
{
	PLyDatumToObFunc func;		/* 转换控制函数 */
	Oid			typoid;			/* 源类型的 OID */
	int32		typmod;			/* 源类型的 typmod */
	bool		typbyval;		/* 其物理表示细节 */
	int16		typlen;
	char		typalign;
	MemoryContext mcxt;			/* 存储此信息的上下文 */
	union						/* 特定于转换类型的数据 */
	{
		PLyScalarToOb scalar;
		PLyArrayToOb array;
		PLyTupleToOb tuple;
		PLyTransformToOb transform;
	}			u;
};

/*
 * 从 Python 对象到 PostgreSQL Datum 的“输出”转换。
 *
 * arg 是先前设置的转换数据，val 是要转换的值。
 *
 * *isnull 在 val 为 Py_None 时设置为 true，否则为 false。
 * （即使对于 Py_None，也必须调用转换函数，
 * 以便可以检查域约束。）
 *
 * inarray 如果转换值在数组（Python 列表）中则为 true。
 * 在某些情况下用于提供更好的错误消息。
 */
typedef struct PLyObToDatum PLyObToDatum;	/* 前向引用 */

typedef Datum (*PLyObToDatumFunc) (PLyObToDatum *arg, PyObject *val,
								   bool *isnull,
								   bool inarray);

typedef struct PLyObToScalar
{
	FmgrInfo	typfunc;		/* 类型的输入函数的查找信息 */
	Oid			typioparam;		/* 传递给它的参数 */
} PLyObToScalar;

typedef struct PLyObToArray
{
	PLyObToDatum *elm;			/* 数组元素类型的转换信息 */
	Oid			elmbasetype;	/* 元素基本类型 */
} PLyObToArray;

typedef struct PLyObToTuple
{
	/* 如果我们处理的是 RECORD 类型，则实际描述符在这里： */
	TupleDesc	recdesc;
	/* 如果我们处理的是命名复合类型，则这些字段被设置： */
	TypeCacheEntry *typentry;	/* 类型的 typcache 条目 */
	uint64		tupdescid;		/* typcache 中看到的最后一个 tupdesc 标识符 */
	/* 如果尚未设置，这些字段为 NULL/0： */
	PLyObToDatum *atts;			/* 每列转换信息的数组 */
	int			natts;			/* 数组的长度 */
	/* 我们可能需要使用 record_in() 进行转换；如果是，就在这里缓存信息 */
	FmgrInfo	recinfunc;		/* record_in 的查找信息 */
} PLyObToTuple;

typedef struct PLyObToDomain
{
	PLyObToDatum *base;			/* 域的基本类型的转换信息 */
	void	   *domain_info;	/* domain_check() 的缓存空间 */
} PLyObToDomain;

typedef struct PLyObToTransform
{
	FmgrInfo	typtransform;	/* to-SQL 转换函数的查找信息 */
} PLyObToTransform;

struct PLyObToDatum
{
	PLyObToDatumFunc func;		/* 转换控制函数 */
	Oid			typoid;			/* 目标类型的 OID */
	int32		typmod;			/* 目标类型的 typmod */
	bool		typbyval;		/* 其物理表示细节 */
	int16		typlen;
	char		typalign;
	MemoryContext mcxt;			/* 存储此信息的上下文 */
	union						/* 特定于转换类型的数据 */
	{
		PLyObToScalar scalar;
		PLyObToArray array;
		PLyObToTuple tuple;
		PLyObToDomain domain;
		PLyObToTransform transform;
	}			u;
};


extern PyObject *PLy_input_convert(PLyDatumToOb *arg, Datum val);
extern Datum PLy_output_convert(PLyObToDatum *arg, PyObject *val,
								bool *isnull);

extern PyObject *PLy_input_from_tuple(PLyDatumToOb *arg, HeapTuple tuple,
									  TupleDesc desc, bool include_generated);

extern void PLy_input_setup_func(PLyDatumToOb *arg, MemoryContext arg_mcxt,
								 Oid typeOid, int32 typmod,
								 struct PLyProcedure *proc);
extern void PLy_output_setup_func(PLyObToDatum *arg, MemoryContext arg_mcxt,
								  Oid typeOid, int32 typmod,
								  struct PLyProcedure *proc);

extern void PLy_input_setup_tuple(PLyDatumToOb *arg, TupleDesc desc,
								  struct PLyProcedure *proc);
extern void PLy_output_setup_tuple(PLyObToDatum *arg, TupleDesc desc,
								   struct PLyProcedure *proc);

extern void PLy_output_setup_record(PLyObToDatum *arg, TupleDesc desc,
									struct PLyProcedure *proc);

/* 从 Python 对象到 C 字符串的转换 --- 为转换导出 */
extern char *PLyObject_AsString(PyObject *plrv);

#endif							/* PLPY_TYPEIO_H */
